package com.cicadalane.androlate;

/*
 * Copyright (C) 2011 cicada.software@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;

import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.statushandlers.StatusManager;
import org.osgi.framework.Bundle;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

import com.cicadalane.androlate.statushandlers.AndrolateStatus;

public class AndrolateApplication {
	private static String mIpAddress = "";
	private static IPath mProjectPath;
	public static final int STRINGLIST_TABLE_MODE_IGNORE = 1;
	public static final int STRINGLIST_TABLE_MODE_TRANSLATE = 0;

	public static final int STRINGLIST_TABLE_NAME_INDEX = 1;
	public static final String[] STRINGLIST_TABLE_TITLES = new String[] {
			"Translate", "Name", "Value" };

	public static final int STRINGLIST_TABLE_TRANSLATE_INDEX = 0;

	public static final int STRINGLIST_TABLE_VALUE_INDEX = 2;

	private static Bundle mBundle = Platform.getBundle(Activator.PLUGIN_ID);
	private static ILog mLog = Platform.getLog(mBundle);

	public static void log(Status status) {
		mLog.log(status);
	}

	public static boolean contains(List<AndrolateOperation> opList,
			AndrolateOperation op) {
		for (int i = 0; i < opList.size(); i++) {
			if (opList.get(i).getFilename().equals(op.getFilename()))
				return true;
		}
		return false;
	}

	public static boolean containsName(List<StringData> sl, String name) {
		for (int i = 0; i < sl.size(); i++) {
			if (sl.get(i).getName().equals(name))
				return true;
		}
		return false;
	}

	public static boolean containsStringData(List<StringData> sl, StringData sd) {
		for (int i = 0; i < sl.size(); i++) {
			if (sl.get(i).hasIndex()) {
				try {
					if (sl.get(i).getName().equals(sd.getName())
							&& sd.getIndex() == sl.get(i).getIndex())
						return true;
				} catch (Exception e) {
					if (sl.get(i).getName().equals(sd.getName()))
						return true;
				}
			} else {
				if (sl.get(i).getName().equals(sd.getName()))
					return true;
			}
		}
		return false;
	}

	private static String getExternalIpAddress() {
		String result = "";
		java.net.URL URL;
		InputStreamReader isr = null;
		try {
			URL = new java.net.URL(
					"http://whatismyip.com/automation/n09230945.asp");

			HttpURLConnection Conn = (HttpURLConnection) URL.openConnection();
			Conn.setConnectTimeout(10000);
			InputStream instream = Conn.getInputStream();
			isr = new java.io.InputStreamReader(instream);
			BufferedReader br = new BufferedReader(isr);
			result = br.readLine();
		} catch (Exception e) {
			result = "";
		} finally {
			if (isr != null) {
				try {
					isr.close();
				} catch (IOException e) { /* ignore */
				}
			}
		}
		return result;
	}

	public static String getIpAddress() {
		if (mIpAddress.isEmpty()) {
			mIpAddress = getExternalIpAddress();
			if (mIpAddress.isEmpty()) {
				try {
					InetAddress addr = InetAddress.getLocalHost();
					byte[] ipAddr = addr.getAddress();
					// Convert to dot representation
					String ipAddrStr = "";
					for (int i = 0; i < ipAddr.length; i++) {
						if (i > 0) {
							ipAddrStr += ".";
						}
						ipAddrStr += ipAddr[i] & 0xFF;
					}
					mIpAddress = ipAddrStr;
				} catch (UnknownHostException e) {
					mIpAddress = "127.0.0.1";
				}
				if (mIpAddress.isEmpty())
					mIpAddress = "127.0.0.1";
			}
		}
		return mIpAddress;
	}

	public static String getLocalizedFilename(String srcFilename,
			AndrolateLanguage lang) {
		return srcFilename.replace(File.separatorChar + "values"
				+ File.separatorChar, File.separatorChar + "values-"
				+ lang.getDirectory() + File.separatorChar);
	}

	public static IPath getProjectPath() {
		return mProjectPath;
	}

	public static IPath getResPath() {
		return getProjectPath().append("res").makeAbsolute();
	}

	public static IPath getResValuesPath() {
		return getResPath().append("values").makeAbsolute();
	}

	private static File mConfigurationFile = null;

	public static void setConfigurationFile(File file) {
		mConfigurationFile = file;
	}

	public static File getConfigurationFile() {
		return mConfigurationFile;
	}

	public static void mergeAndrolateObjects(Androlate src, Androlate dest) {
		ArrayList<AndrolateOperation> srcOperations = src.getOperations();
		ArrayList<AndrolateOperation> destOperations = dest.getOperations();
		for (AndrolateOperation srco : srcOperations) {
			for (AndrolateOperation desto : destOperations) {
				if (srco.getFilename().equals(desto.getFilename())) {
					for (StringData srcs : srco.getTranslateList()) {
						if (AndrolateApplication.containsName(desto
								.getAllStringsList(), srcs.getName())
								&& !AndrolateApplication.containsName(desto
										.getTranslateList(), srcs.getName())) {
							StringData sd = AndrolateApplication.getStringData(
									desto.getAllStringsList(), srcs.getName());
							desto.getTranslateList().add(sd);
						}
					}
					for (StringData srcs : srco.getIgnoreList()) {
						if (AndrolateApplication.containsName(desto
								.getAllStringsList(), srcs.getName())
								&& !AndrolateApplication.containsName(desto
										.getIgnoreList(), srcs.getName())) {
							StringData sd = AndrolateApplication.getStringData(
									desto.getAllStringsList(), srcs.getName());
							desto.getTranslateList().add(sd);
							desto.getIgnoreList().add(sd);
						}
					}
				}
			}
		}

		ArrayList<AndrolateLanguage> srcLanguages = src.getTargetLanguages();
		ArrayList<AndrolateLanguage> destLanguages = dest.getTargetLanguages();
		for (AndrolateLanguage srcLanguage : srcLanguages) {
			boolean found = false;
			for (AndrolateLanguage destLanguage : destLanguages) {
				if (srcLanguage.getDirectory().equals(
						destLanguage.getDirectory())) {
					found = true;
					break;
				}
			}
			if (!found) {
				destLanguages.add(srcLanguage);
			}
		}
	}

	public static int removeStringData(List<StringData> sl, StringData sd) {
		int result = 0;
		for (int i = sl.size() - 1; i >= 0; i--) {
			if (sl.get(i).hasIndex()) {
				try {
					if (sl.get(i).getName().equals(sd.getName())
							&& sd.getIndex() == sl.get(i).getIndex()) {
						sl.remove(i);
						result++;
					}
				} catch (Exception e) {
					if (sl.get(i).getName().equals(sd.getName())) {
						sl.remove(i);
						result++;
					}
				}
			} else if (sl.get(i).getName().equals(sd.getName())) {
				sl.remove(i);
				result++;
			}
		}
		return result;
	}

	public static void setProjectPath(IPath path) {
		mProjectPath = path;
	}

	public static String stringIntersection(String s1, String s2) {
		if (s1.startsWith(s2)) {
			return s1.replace(s2, "");
		}
		return s1;
	}

	public static boolean stringListContains(List<StringData> sl, String name) {
		if (sl == null || sl.size() == 0)
			return false;

		for (StringData v : sl) {
			if (v.getName().equals(name))
				return true;
		}
		return false;
	}

	public static StringData getStringData(List<StringData> sl, String name) {
		if (sl == null || sl.size() == 0)
			return null;

		for (StringData v : sl) {
			if (v.getName().equals(name))
				return v;
		}
		return null;
	}

	public static StringData translateStringValue(StringData s,
			AndrolateLanguage from, AndrolateLanguage to) throws Exception {
		StringData result = new StringData();
		result.setName(s.getName());

		String translatedString = GoogleTranslate.translate(s.getValue(), from,
				to);
		result.setValue(translatedString);
		return result;
	}

	private Androlate mAndrolateObject;

	public AndrolateApplication(IPath projectPath) {
		mAndrolateObject = new Androlate();
		AndrolateApplication.setProjectPath(projectPath);
	}

	public void createOperations(File[] resourceXmlfiles)
			throws ParserConfigurationException, SAXException, IOException,
			TransformerFactoryConfigurationError, TransformerException {
		if (resourceXmlfiles == null || resourceXmlfiles.length <= 0)
			return;

		for (int i = 0; i < resourceXmlfiles.length; i++) {
			final File f = resourceXmlfiles[i];
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			Document dom = null;
			DocumentBuilder db = dbf.newDocumentBuilder();
			dom = db.parse(f);
			if (dom == null)
				continue;

			Element documentElement = dom.getDocumentElement();
			if (documentElement == null)
				continue;

			// create a mapping between filename and string elements
			String nodeName = documentElement.getNodeName();
			if (nodeName != null && nodeName.equals("resources")) {
				List<Element> stringElements = XmlUtils.getChildrenByTagName(
						dom.getDocumentElement(), new String[] { "string",
								"string-array" });
				if (stringElements == null)
					continue;

				AndrolateOperation operation = new AndrolateOperation();
				operation.setFilename(f.getAbsolutePath());

				if (stringElements.size() > 0) {
					for (int nli = 0; nli < stringElements.size(); nli++) {
						if (stringElements.get(nli) instanceof Element) {
							Element e = (Element) stringElements.get(nli);
							if (e.getAttribute("name") != null
									&& e.getAttribute("name").length() > 0) {
								if (e.getNodeName().equals("string-array")) {
									List<Element> itemElements = XmlUtils
											.getChildrenByTagName(e, "item");
									for (int ii = 0; ii < itemElements.size(); ii++) {
										StringData s = new StringData();
										s.setName(e.getAttribute("name"));
										s.setValue(XmlUtils
												.getInnerXml(itemElements
														.get(ii)));
										s.setIndex(ii);
										operation.getAllStringsList().add(s);
									}
								} else {
									StringData s = new StringData();
									s.setName(e.getAttribute("name"));
									s.setValue(XmlUtils.getInnerXml(e));
									operation.getAllStringsList().add(s);
								}
							}
						}
					}
					updateOperation(operation);
				}
			}
		}
	}

	public Androlate getAndrolate() {
		return mAndrolateObject;
	}

	public Document initializeDocument(File file, boolean backup)
			throws Exception {
		String filename = file.getAbsolutePath();
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		Document dom = null;
		DocumentBuilder db = dbf.newDocumentBuilder();
		if (file.exists()) {
			if (backup) {
				Date d = new Date();
				SimpleDateFormat format = new SimpleDateFormat(
						"yyyy-MM-dd_HH-mm-ss");
				FileUtils.copyFile(filename, filename + "-" + format.format(d)
						+ ".bak");
			}
			dom = db.parse(filename);
		} else
			dom = db.newDocument();

		if (dom == null)
			throw new Exception(filename + " DOM object is null");

		return dom;

	}

	public boolean isTransationRequested(AndrolateOperation op) {
		if (op == null)
			return false;
		if (op.getTranslateList() == null || op.getTranslateList().size() == 0)
			return false;

		return true;
	}

	/*
	 * removes a given language from the list of target languages
	 */
	public void removeTargetLanguage(AndrolateLanguage language) {
		for (int i = getAndrolate().getTargetLanguages().size() - 1; i >= 0; i--) {
			AndrolateLanguage l = getAndrolate().getTargetLanguages().get(i);
			if (l.getDirectory().equals(language.getDirectory()))
				getAndrolate().getTargetLanguages().remove(l);
		}
	}

	public void reset() {
		getAndrolate().getTargetLanguages().clear();
		getAndrolate().getOperations().clear();
	}

	/*
	 * Filters out the Ignore strings from the Translate strings to only give
	 * you what you want
	 */
	public ArrayList<StringData> resolveStringOperations(Androlate a) {
		ArrayList<StringData> result = new ArrayList<StringData>();
		for (AndrolateLanguage l : a.getTargetLanguages()) {
			for (AndrolateOperation o : a.getOperations()) {
				ArrayList<StringData> oresult = resolveStringOperations(o, l);
				result.addAll(oresult);
			}
		}
		return result;
	}

	private static ArrayList<StringData> getStringDataFromElement(
			List<Element> elements) {
		ArrayList<StringData> result = new ArrayList<StringData>();
		for (Element element : elements) {
			try {
				if (element.getNodeName().equals("string-array")) {
					String name = element.getAttribute("name");
					List<Element> itemElements = XmlUtils.getChildrenByTagName(
							element, "item");
					for (int i = 0; i < itemElements.size(); i++) {
						StringData sd = new StringData();
						sd.setName(name);
						sd.setValue(XmlUtils.getInnerXml(itemElements.get(i)));
						sd.setIndex(i);
						result.add(sd);
					}
				} else if (element.getNodeName().equals("string")) {
					StringData sd = new StringData();
					sd.setName(element.getAttribute("name"));
					sd.setValue(XmlUtils.getInnerXml(element));
					result.add(sd);
				}
			} catch (Exception e) { /* ignored */
			}
		}
		return result;
	}

	/*
	 * Filters out the Ignore strings from the Translate strings to only give
	 * you what you want
	 */
	public ArrayList<StringData> resolveStringOperations(
			AndrolateOperation operation, AndrolateLanguage lang) {
		ArrayList<StringData> result = new ArrayList<StringData>();

		String srcFilename = operation.getFilename();
		String destFilename = AndrolateApplication.getLocalizedFilename(
				srcFilename, lang);
		File destFile = new File(destFilename);

		Document domSrc = null;
		Element srcDocumentElement = null;
		List<Element> srcStringElements = null;
		try {
			domSrc = initializeDocument(new File(srcFilename), false);

			srcDocumentElement = domSrc.getDocumentElement();
			if (srcDocumentElement != null
					&& !srcDocumentElement.getNodeName().equals("resources")) {
				throw new Exception(srcFilename
						+ " DocumentElement is not of type resources");
			}

			srcStringElements = XmlUtils.getChildrenByTagName(
					srcDocumentElement,
					new String[] { "string", "string-array" });
		} catch (Exception ignored) {
			srcDocumentElement = null;
		}

		if (srcStringElements == null || srcStringElements.size() == 0) {
			return new ArrayList<StringData>();
		}

		String overwriteOptionString = getAndrolate().getOption(
				Androlate.OPTION_KEY_OVERWRITE_EXISTING);
		boolean overwriteOption = Boolean.parseBoolean(overwriteOptionString);

		String submitUnchangedOptionString = getAndrolate().getOption(
				Androlate.OPTION_KEY_SUBMIT_UNCHANGED);
		boolean submitUnchangedOption = Boolean
				.parseBoolean(submitUnchangedOptionString);

		Androlate saved = null;
		File configFile = getConfigurationFile();
		if (configFile != null && configFile.exists()) {
			try {
				saved = new Androlate();
				saved.loadFromFile(configFile);
			} catch (Exception e) {
				saved = null;
			}
		}

		List<AndrolateOperation> savedOperations = null;
		if (saved != null)
			savedOperations = saved.getOperations();

		// filter out values if the haven't changed
		ArrayList<StringData> modifiedStringData = new ArrayList<StringData>();
		if (savedOperations != null && !submitUnchangedOption) {
			for (AndrolateOperation savedOperation : savedOperations) {
				if (savedOperation.getFilename().equals(srcFilename)) {
					List<StringData> sdlist = AndrolateApplication
							.getStringDataFromElement(srcStringElements);
					for (StringData sd : sdlist) {
						ArrayList<StringData> allStrings = savedOperation
								.getAllStringsList();
						for (StringData allString : allStrings) {
							if (allString.isSimilar(sd)
									&& !allString.equals(sd)) {
								modifiedStringData.add(sd);
							}
						}
					}
				}
			}
		} else {
			List<StringData> sdlist = AndrolateApplication
					.getStringDataFromElement(srcStringElements);
			modifiedStringData.addAll(sdlist);
		}

		ArrayList<StringData> existingValues = new ArrayList<StringData>();
		try {
			if (destFile.exists() && !overwriteOption) {
				Document domDest = null;
				domDest = initializeDocument(destFile, false);

				Element destDocumentElement = domDest.getDocumentElement();
				if (destDocumentElement != null
						&& destDocumentElement.getNodeName()
								.equals("resources")) {

					List<Element> stringElements = XmlUtils
							.getChildrenByTagName(destDocumentElement,
									new String[] { "string", "string-array" });

					List<StringData> destinationStringDataList = AndrolateApplication
							.getStringDataFromElement(stringElements);

					for (StringData destinationStringData : destinationStringDataList) {
						if (AndrolateApplication.containsStringData(
								modifiedStringData, destinationStringData)) {
							existingValues.add(destinationStringData);
						}
					}
				}
			}
		} catch (Exception e) {
		}

		ArrayList<StringData> oresult = resolveStringOperations(operation,
				existingValues);
		result.addAll(oresult);
		return result;
	}

	/*
	 * Filters out the Ignore strings from the Translate strings to only give
	 * you what you want
	 */
	public ArrayList<StringData> resolveStringOperations(
			AndrolateOperation operation,
			ArrayList<StringData> existingStringData) {
		ArrayList<StringData> result = new ArrayList<StringData>();
		ArrayList<StringData> tl = operation.getTranslateList();
		ArrayList<StringData> il = operation.getIgnoreList();

		NEXT_STRING: for (StringData tsv : tl) {
			if (AndrolateApplication.containsName(il, tsv.getName()))
				continue; /* don't include name if name is specified as ignored */

			for (StringData existingStringDatum : existingStringData) {
				if (tsv.equals(existingStringDatum))
					continue NEXT_STRING;
			}
			result.add(tsv);
		}
		return result;
	}

	public void saveFile(String filename) throws Exception {
		Androlate androlate = getAndrolate();
		androlate.writeToFile(filename);
	}

	public void TranslateOperation(AndrolateOperation op,
			AndrolateLanguage lang, ArrayList<StringData> sl,
			IProgressMonitor monitor) throws Exception {
		if (op == null)
			throw new Exception("required op argument is null");

		if (sl == null)
			throw new Exception("required sl argument is null");

		String backupOptionString = getAndrolate().getOption(
				Androlate.OPTION_KEY_BACKUP_FILES);
		boolean backupOption = Boolean.parseBoolean(backupOptionString);

		String srcFilename = op.getFilename();
		String destFilename = AndrolateApplication.getLocalizedFilename(
				srcFilename, lang);
		File destFile = new File(destFilename);

		Document domSrc = null;
		domSrc = initializeDocument(new File(srcFilename), false);

		Document domDest = null;
		domDest = initializeDocument(destFile, backupOption);

		Element srcDocumentElement = domSrc.getDocumentElement();
		if (srcDocumentElement == null)
			throw new Exception(srcFilename + " DocumentElement is null");

		if (!srcDocumentElement.getNodeName().equals("resources")) {
			throw new Exception(srcFilename
					+ " DocumentElement is not of type resources");
		}

		Element destDocumentElement = domDest.getDocumentElement();
		if (destDocumentElement == null) {
			destDocumentElement = domDest.createElement("resources");
			domDest.appendChild(destDocumentElement);
		}

		if (!destDocumentElement.getNodeName().equals("resources")) {
			throw new Exception(destFilename
					+ " DocumentElement is not of type resources");
		}

		// copy src namespaces into output document
		int srcgetAttributesLength = srcDocumentElement.getAttributes()
				.getLength();
		for (int i = 0; i < srcgetAttributesLength; i++) {
			Node attrNode = srcDocumentElement.getAttributes().item(i);
			destDocumentElement.setAttribute(attrNode.getNodeName(), attrNode
					.getNodeValue());
		}

		for (StringData stringValue : sl) {
			if (monitor.isCanceled())
				return;

			Thread.sleep(2000); // throttle outselves to prevent google from
								// blocking out requests

			String nameValue = stringValue.getName();
			String filenameDisplay = op.getFilename();
			java.io.File projectFilePath = AndrolateApplication
					.getProjectPath().toFile();
			filenameDisplay = AndrolateApplication.stringIntersection(
					filenameDisplay, projectFilePath.getAbsolutePath());
			monitor.subTask(filenameDisplay + " : " + lang.getDisplay() + ": "
					+ nameValue);

			Status status = new Status(IStatus.INFO, Activator.PLUGIN_ID,
					AndrolateStatus.INFO, "Translating: " + filenameDisplay
							+ " : " + lang.getDisplay() + ": " + nameValue,
					null);

			AndrolateApplication.log(status);

			String translatedString = "";
			String val = stringValue.getValue();
			String resultXml = "";
			DocumentFragment docFrag = XmlUtils.parseFragment(domSrc, val);
			try {
				for (int i = 0; i < docFrag.getChildNodes().getLength(); i++) {
					String xmlval = null;
					Node n = docFrag.getChildNodes().item(i);
					switch (n.getNodeType()) {
					case Node.ELEMENT_NODE:
						xmlval = XmlUtils.getInnerXml(n);
						translatedString = GoogleTranslate.translate(xmlval,
						Language.ENGLISH, lang);
						n.setTextContent(translatedString);
						resultXml += XmlUtils.getOuterXml(n);
						break;
					case Node.TEXT_NODE:
						xmlval = n.getTextContent();
						translatedString = GoogleTranslate.translate(xmlval,
						Language.ENGLISH, lang);
						n.setTextContent(translatedString);
						resultXml += XmlUtils.getOuterXml(n);
						break;
					}
				}

				Status retstatus = new Status(IStatus.INFO,
						Activator.PLUGIN_ID, AndrolateStatus.INFO, "Sent: "
								+ val + "; Result: " + translatedString, null);

				AndrolateApplication.log(retstatus);

			} catch (Exception e) {
				throw new Exception("Google Translate Error: " + e.getMessage());
			}
			updateDestinationDocument(stringValue, destDocumentElement,
					resultXml);
			monitor.worked(1);
		}
		try {
			if (!destFile.exists()) {
				destFile.getParentFile().mkdirs();
				destFile.createNewFile();
			}
			XmlUtils.writeXmlFile(domDest, destFilename);
		} catch (Exception e) {
			throw new Exception("Error saving XML" + e.getMessage());
		}

	}

	private void updateDestinationDocument(StringData stringValue,
			Element documentElement, String translatedString) throws Exception {
		List<Element> stringElements = XmlUtils.getChildrenByTagName(
				documentElement, new String[] { "string", "string-array" });
		Document doc = documentElement.getOwnerDocument();

		boolean elementFound = false;

		for (int i = 0; i < stringElements.size(); i++) {
			if (!(stringElements.get(i) instanceof Element))
				continue;
			Element stringElement = (Element) stringElements.get(i);
			String nameValue = stringElement.getAttribute("name");

			if (nameValue.equals(stringValue.getName())) {
				if (stringElement.getNodeName().equals("string-array")) {
					updateStringArrayElement(stringValue, translatedString,
							doc, stringElement);
				} else if (nameValue.equals(stringValue.getName())
						&& mAndrolateObject.getIsOverwriteExistingSet()) {
					XmlUtils.setInnerXml(stringElement, translatedString);
				}
				elementFound = true;
			}
		}

		if (elementFound)
			return;

		// element not found, so lets create one
		if (stringValue.hasIndex()) {
			Element stringElement = doc.createElement("string-array");
			stringElement.setAttribute("name", stringValue.getName());
			updateStringArrayElement(stringValue, translatedString, doc,
					stringElement);
			documentElement.appendChild(stringElement);
		} else {
			Element stringElement = doc.createElement("string");
			stringElement.setAttribute("name", stringValue.getName());
			XmlUtils.setInnerXml(stringElement, translatedString);
			documentElement.appendChild(stringElement);
		}
		return;
	}

	/*
	 * Add a new operation to the Androlate object, or replace it if the
	 * filename matches
	 */
	public void updateOperation(AndrolateOperation operation) {
		for (int i = getAndrolate().getOperations().size() - 1; i >= 0; i--) {
			AndrolateOperation o = this.getAndrolate().getOperations().get(i);
			if (o.getFilename().equals(operation.getFilename()))
				this.getAndrolate().getOperations().remove(o);
		}
		getAndrolate().getOperations().add(operation);
	}

	private void updateStringArrayElement(StringData stringValue, String text,
			Document document, Element stringArrayElement) throws Exception {
		if (!stringValue.hasIndex())
			throw new Exception(
					"updateStringArrayElement stringdata is missing index");

		int index = stringValue.getIndex();

		List<Element> itemElements = XmlUtils.getChildrenByTagName(
				stringArrayElement, "item");
		if (index < itemElements.size()) {
			if (mAndrolateObject.getIsOverwriteExistingSet()) {
				XmlUtils.setInnerXml(itemElements.get(index), text);
			}
		} else {
			Element itemElement = null;

			while (index > itemElements.size()) {
				itemElement = document.createElement("item");
				stringArrayElement.appendChild(itemElement);
				itemElements = XmlUtils.getChildrenByTagName(
						stringArrayElement, "item");
			}

			itemElement = document.createElement("item");
			XmlUtils.setInnerXml(itemElement, text);
			stringArrayElement.appendChild(itemElement);
		}
	}

	/*
	 * Add a new Language to the Androlate object, or replace it if the filename
	 * matches
	 */
	public void updateTargetLanguage(AndrolateLanguage language) {
		removeTargetLanguage(language);
		getAndrolate().getTargetLanguages().add(language);
	}
}
